home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / swagg_m.zip / MEMORY.SWG / 0069_Heap Memory Integrity Checking.pas < prev   
Pascal/Delphi Source File  |  1995-03-03  |  6KB  |  209 lines

  1. {
  2. From: dmurdoch@mast.queensu.ca (Duncan Murdoch)
  3. >
  4. >Anyhow, what this program is doing (among other things) is reading data from
  5. >an ASCII file when commanded to, one line at a time, and plotting it on the
  6. >screen.  My problem is, when you return to the main menu, a bit of the RAM
  7. >has been used.  If you call up a couple of plots in a row, eventually you
  8. >run out of RAM and crash.  And I'm having a devil of a time trying to figure
  9. >where the memory is going.
  10.  
  11. This is one of the harder kinds of error to track down.  The way I do it is
  12. as follows:
  13.  
  14. 1.  Throughout program development, I use a debugging unit that warns me if
  15. anything is left on the heap when the program terminates. If there is, I
  16. immediately track it down and fix it.  The error is probably in the new
  17. part, and that helps to find it.
  18.  
  19. 2.  To prevent errors, I program in a very structured way:  every allocation
  20. has a matching de-allocation, preferable within a dozen or two lines of
  21. it so they're both on screen at once and I can see that they match.
  22.  
  23. 3.  If the preventive methods don't work, I have to track down the bugs. I
  24. have a routine that can print heap usage when I want.  I print all the heap
  25. that's used at the end of the program (should be none!), and try to
  26. recognize where the stuff came from.  If it's strings, it's easy, but if
  27. it's binary data, it's hard.  If necessary I trace through the program until
  28. I see one of those parts get allocated.
  29.  
  30. I've attached my heap routine below, but it won't compile for you without a
  31. few utility routines from TurboPower's Object Professional library (and
  32. some others of mine).  Hopefully it'll still be useful for you and you can
  33. write the other parts yourself.
  34.  
  35. Duncan Murdoch
  36. }
  37. unit heap;
  38. { This unit does integrity checks on the TP 6.0 heap }
  39.  
  40. interface
  41.  
  42. uses standard,opinline,opstring,dump;
  43.  
  44. function heapokay:boolean;
  45.  
  46. procedure showfreelist(var where:text;msg:string);
  47. { Prints the free list }
  48.  
  49. procedure showheapused(var where:text;msg:string);
  50. { Prints the heap usage }
  51.  
  52. type
  53.   PFreeRec = ^TFreeRec;
  54.   TFreeRec = record
  55.     next: PFreeRec;
  56.     size: Pointer;
  57.   end;
  58.  
  59.  
  60. implementation
  61.  
  62. function Ordered(p1,p2:pointer):boolean;
  63. { Tests whether p1 <= p2 }
  64. begin
  65.   Ordered := PtrToLong(p1) <= PtrToLong(p2);
  66. end;
  67.  
  68. function Normed(p:pointer):boolean;
  69. { Checks whether p is a normalized pointer }
  70. begin
  71.   case ofs(p^) of
  72.   0..$F : Normed := true;
  73.   else    Normed := false;
  74.   end;
  75. end;
  76.  
  77. function heapokay:boolean;
  78.  
  79. procedure error(msg:string);
  80. begin
  81.   writeln(stderr,msg);
  82.   heapokay := false;
  83.   halt(99);
  84. end;
  85.  
  86. type
  87.   PFreeRec = ^TFreeRec;
  88.   TFreeRec = record
  89.     next: PFreeRec;
  90.     size: Pointer;
  91.   end;
  92. var
  93.   FreeRec : PFreeRec;
  94. begin
  95.   if not Normed(HeapOrg) then
  96.     error('HeapOrg bad!');
  97.   if not Normed(FreeList) then
  98.     error('FreeList bad!');
  99.   if not Normed(HeapPtr) then
  100.     error('HeapPtr bad!');
  101.   if not Normed(HeapEnd) then
  102.     error('HeapEnd bad!');
  103.  
  104.   if not Ordered(HeapOrg,FreeList) then
  105.     error('HeapOrg > FreeList');
  106.   if not Ordered(FreeList,HeapPtr) then
  107.     error('FreeList > HeapPtr');
  108.   if not Ordered(HeapPtr,HeapEnd) then
  109.     error('HeapPtr > HeapEnd');
  110.  
  111.   FreeRec := FreeList;
  112.   while PtrToLong(FreeRec) < PtrToLong(HeapPtr) do   { Walk the free list }
  113.   begin
  114.     if not Normed(FreeRec^.next) then
  115.       error('Bad next in free record '+HexPtr(FreeRec));
  116.     if not ordered(FreeRec,FreeRec^.next) then
  117.       error('self > next in free record '+HexPtr(FreeRec));
  118.     if not ordered(AddLongToPtr(FreeRec,PtrToLong(FreeRec^.size)),
  119.                    FreeRec^.next) then
  120.       error('Bad size in free record '+HexPtr(FreeRec));
  121.     if FreeRec = FreeRec^.Next then
  122.       error('Self pointer in free record '+HexPtr(FreeRec));
  123.     FreeRec := FreeRec^.Next;
  124.   end;
  125.   if FreeRec <> HeapPtr then
  126.     error('Bad last free block');
  127.  
  128.   heapokay := true;
  129. end;
  130.  
  131. function addtopointer(p:pointer;incr:longint):pointer;
  132. {  Adds increment to pointer, only normalizes if necessary }
  133. begin
  134.   if ofs(p^) + incr > 65535 then
  135.     addtopointer := AddLongToPtr(p,incr)
  136.   else
  137.     addtopointer := AddWordToPtr(p,incr);
  138. end;
  139.  
  140. procedure showfreelist(var where:text;msg:string);
  141. { Prints the free list }
  142. var
  143.   FreePtr : PFreerec;
  144.   Free,Total:longint;
  145. begin
  146.   writeln(where,msg);
  147.   writeln(where,'  Start      Stop    Size free');
  148.  
  149.   FreePtr := PFreeRec(@FreeList);
  150.   Total := 0;
  151.   repeat
  152.     Free:=PtrToLong(Freeptr^.Size);
  153.     inc(Total,Free);
  154.     if Free <> 0 then
  155.       writeln(where, HexPtr(FreePtr), '  ', HexPtr(AddToPointer(FreePtr,Free)),
  156.                      '  ',Free:6);
  157.     FreePtr := FreePtr^.next;
  158.   until FreePtr = HeapPtr;
  159.   Free := PtrDiff(HeapEnd,HeapPtr);
  160.   inc(Total,Free);
  161.   writeln(where, HexPtr(HeapPtr), '  ', HexPtr(HeapEnd),
  162.                  '  ',Free:6);
  163.   writeln(where, 'Total':8,'':14, Total:6);
  164. end;
  165.  
  166. procedure showheapused(var where:text;msg:string);
  167. { Prints what's been used on the heap }
  168. var
  169.   FreePtr : PFreerec;
  170.   UsedPtr : Pointer;
  171.   Used : longint;
  172.   Total: longint;
  173. begin
  174.   writeln(where,msg);
  175.   writeln(where,'  Start      Stop    Size used     Data');
  176.  
  177.   FreePtr := FreeList;
  178.   UsedPtr := HeapOrg;
  179.   total := 0;
  180.   while FreePtr <> HeapPtr do
  181.   begin
  182.     Used := PtrDiff(UsedPtr,FreePtr);
  183.     inc(Total,Used);
  184.     if used <> 0 then
  185.     begin
  186.       write(where, HexPtr(UsedPtr), '  ', HexPtr(AddToPointer(UsedPtr,Used)),
  187.                      '  ',Used:6,'   ');
  188.       dumpbothshort(where, UsedPtr^, 0, 8);
  189.     end;
  190.  
  191.     UsedPtr := AddLongToPtr(FreePtr,PtrToLong(FreePtr^.size));
  192.     if FreePtr <> HeapPtr then
  193.       FreePtr := FreePtr^.next;
  194.   end;
  195.   Used := PtrDiff(HeapPtr,UsedPtr);
  196.   inc(Total,used);
  197.   if used <> 0 then
  198.   begin
  199.     write(where, HexPtr(UsedPtr), '  ', HexPtr(AddToPointer(UsedPtr,Used)),
  200.                      '  ',Used:6,'   ');
  201.     dumpbothshort(where, UsedPtr^, 0,8);
  202.   end;
  203.   writeln(where, 'Total':8,'':14, Total:6);
  204. end;
  205.  
  206.  
  207. end.
  208.  
  209.